package com.zmn.mcc.business.impl.permit;

import com.alibaba.fastjson.JSONObject;
import com.zmn.base.plat.engine.common.constant.DubboConsts;
import com.zmn.base.plat.engine.common.constant.PlatEngineConsts;
import com.zmn.base.plat.engine.common.exception.ZmnPlatException;
import com.zmn.base.product.common.consts.BaseProductConsts;
import com.zmn.base.product.common.dto.product.erp.ProductGroupDRO;
import com.zmn.base.product.dubbo.interfaces.product.foreign.ProductGroupForeignListRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.dpermit.product.DpermitProductGroupBService;
import com.zmn.mcc.business.interfaces.permit.PermitBService;
import com.zmn.mcc.business.interfaces.staff.StaffBService;
import com.zmn.mcc.common.constant.DpermitConsts;
import com.zmn.mcc.common.dto.permit.PermitDRO;
import com.zmn.mcc.common.dto.permit.PermitLitDO;
import com.zmn.mcc.common.dto.permit.PermitTreeDRO;
import com.zmn.mcc.common.dto.permit.SpermitDTO;
import com.zmn.mcc.model.dto.dpermit.DpermitBaseDO;
import com.zmn.mcc.model.dto.dpermit.DpermitSimpleDO;
import com.zmn.mcc.model.entity.dept.McDeptDpermit;
import com.zmn.mcc.model.entity.dept.McDeptDpermitQuery;
import com.zmn.mcc.model.entity.organize.McOrganize;
import com.zmn.mcc.model.entity.organize.McOrganizeQuery;
import com.zmn.mcc.model.entity.permit.McPermit;
import com.zmn.mcc.model.entity.staff.McStaff;
import com.zmn.mcc.model.entity.staff.McStaffDpermit;
import com.zmn.mcc.model.entity.staff.McStaffDpermitQuery;
import com.zmn.mcc.model.entity.sys.McSys;
import com.zmn.mcc.model.entity.sys.McSysQuery;
import com.zmn.mcc.services.interfaces.dept.DeptDpermitService;
import com.zmn.mcc.services.interfaces.organize.OrganizeService;
import com.zmn.mcc.services.interfaces.permit.PermitService;
import com.zmn.mcc.services.interfaces.staff.StaffDpermitService;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import com.zmn.mcc.services.interfaces.sys.SysService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.zmn.mcc.common.constant.DpermitConsts.*;

/**
 * @author heguanghua
 * @since 2020/04/14 22:23
 */
@Service
public class PermitBServiceImpl implements PermitBService {
    protected Logger logger = LoggerFactory.getLogger(PermitBServiceImpl.class);

    @Resource
    private PermitService permitService;

    @Resource
    private StaffService staffService;

    @Resource
    private StaffBService staffBService;

    @Resource
    private SysService sysService;

    @Resource
    private OrganizeService organizeService;

    @Resource
    private DeptDpermitService deptDpermitService;

    @Resource
    private StaffDpermitService staffDpermitService;

    @Resource
    private DpermitProductGroupBService dpermitProductGroupBService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private ProductGroupForeignListRemoteService productGroupListRemoteService;

    private final static Integer TOP_LEVEL = 0;


    // region 根据角色查询简化权限对象列表

    @Override
    @ReadOnlyConnection
    public List<PermitLitDO> listPermitLitByRoleIds(List<Integer> roleIds, Integer sysId) {
        return permitService.listPermitLitBySysIdAndRoleIds(roleIds, sysId);
    }
    // endregion

    // region 新增/修改权限


    @Override
    public List<PermitDRO> listOrgPermitByStaffId(Integer staffId) {

        // 查询员工信息
        McStaff staff = staffService.findByKey(staffId);

        Optional.ofNullable(staff).orElseThrow(() -> new ZmnPlatException("无效的员工ID！"));
        // 查询所有的org
        McOrganizeQuery mcOrganizeQuery = new McOrganizeQuery();
        mcOrganizeQuery.setStatus(PlatEngineConsts.STATUS_VALID);

        Map<Integer, List<PermitDRO>> listMap = Optional.ofNullable(organizeService.listByQuery(mcOrganizeQuery)).orElse(Collections.emptyList())
                .stream().collect(Collectors.groupingBy(McOrganize::getParentId, Collectors.mapping(x -> PermitDRO.builder()
                        .permitId(x.getOrgId()).permitName(x.getOrgName()).parentId(x.getParentId()).level(x.getLevel()).build(), Collectors.toList())));
        if (CollectionUtil.isNullOrEmpty(listMap)) {
            return Collections.emptyList();
        }

        // 查询员工权限
        McStaffDpermitQuery query = new McStaffDpermitQuery();
        query.setDataType(DpermitConsts.TYPE_ORGANIZE);
        query.setStaffId(staffId);
        List<McStaffDpermit> mcStaffDpermits = staffDpermitService.listByQuery(query);

        if (CollectionUtil.isNotNullOrEmpty(mcStaffDpermits)) {
            return getSubPermit(listMap, mcStaffDpermits);
        }

        // 查询部门
        McDeptDpermitQuery deptDpermitQuery = new McDeptDpermitQuery();
        deptDpermitQuery.setDataType(DpermitConsts.TYPE_ORGANIZE);
        deptDpermitQuery.setDeptId(staff.getDeptId());
        List<McDeptDpermit> mcDeptDpermits = deptDpermitService.listByQuery(deptDpermitQuery);

        if (CollectionUtil.isNotNullOrEmpty(mcDeptDpermits)) {
            return getSubPermit(listMap, mcDeptDpermits);
        }

        // 没有 默认就是拥有全部的权限
        // 查询组织架构或者部门
        return listMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
    }

    @Override
    public List<PermitTreeDRO> listProductPermitByStaffId(Integer staffId) {

        // 查询员工信息
        McStaff staff = staffService.findByKey(staffId);

        Optional.ofNullable(staff).orElseThrow(() -> new ZmnPlatException("无效的员工ID！"));

        // 查询所有的product
        List<DpermitSimpleDO> dpermitSimpleDOS = dpermitProductGroupBService.listProductGroupAndDpermitChecked(PlatEngineConsts.STATUS_VALID, null);

        if (CollectionUtil.isNullOrEmpty(dpermitSimpleDOS)) {
            return Collections.emptyList();
        }
        ResponseDTO<List<ProductGroupDRO>> responseDTO = productGroupListRemoteService.listTreeByStatus(PlatEngineConsts.STATUS_VALID);
        Map<String, List<PermitTreeDRO>> groupMap = new HashMap<>();
        if (responseDTO.isSuccess()) {
            List<ProductGroupDRO> data = responseDTO.getData().stream().filter(x -> Objects.nonNull(x.getGroupId())).collect(Collectors.toList());
            // 一级业务线
            //c-保外
            PermitTreeDRO cDepermitDO = new PermitTreeDRO();
            cDepermitDO.setPermitId(BaseProductConsts.BIZ_TYPE_C);
            cDepermitDO.setPermitName(BaseProductConsts.BIZ_TYPE_C_EN_CN);
            cDepermitDO.setParentId(TOP_LEVEL);
            cDepermitDO.setLevel(PRODUCT_LEVEL_BIZTYPE);
            cDepermitDO.setDataSubAll(PlatEngineConsts.STATUS_INVALID);

            //f-保内
            PermitTreeDRO fDepermitDO = new PermitTreeDRO();
            fDepermitDO.setPermitId(BaseProductConsts.BIZ_TYPE_F);
            fDepermitDO.setPermitName(BaseProductConsts.BIZ_TYPE_F_EN_CN);
            fDepermitDO.setParentId(TOP_LEVEL);
            fDepermitDO.setLevel(PRODUCT_LEVEL_BIZTYPE);
            fDepermitDO.setDataSubAll(PlatEngineConsts.STATUS_INVALID);

            //B-工程业务
            PermitTreeDRO bDepermitDO = new PermitTreeDRO();
            bDepermitDO.setPermitId(BaseProductConsts.BIZ_TYPE_B);
            bDepermitDO.setPermitName(BaseProductConsts.BIZ_TYPE_B_EN_CN);
            bDepermitDO.setParentId(TOP_LEVEL);
            bDepermitDO.setLevel(PRODUCT_LEVEL_BIZTYPE);
            bDepermitDO.setDataSubAll(PlatEngineConsts.STATUS_INVALID);

            groupMap.put(TOP_LEVEL + "_" + PRODUCT_LEVEL_BIZTYPE, Arrays.asList(cDepermitDO, fDepermitDO, bDepermitDO));

            // 二级产品线
            Map<String, Set<PermitTreeDRO>> bizs = data.stream().collect(Collectors.groupingBy(x -> x.getBizType() + "_" + PRODUCT_LEVEL_BIZLINE, Collectors.mapping(x -> PermitTreeDRO.builder().permitId(x.getBizLine()).permitName(x.getBizLineName()).parentId(x.getBizType()).level(PRODUCT_LEVEL_BIZLINE).dataSubAll(PlatEngineConsts.STATUS_INVALID).build(), Collectors.toSet())));

            bizs.forEach((x, y) -> groupMap.put(x, new ArrayList<>(y)));

            // 三级产品组
            Map<String, List<PermitTreeDRO>> groups = data.stream().collect(Collectors.groupingBy(x -> x.getBizLine() + "_" + PRODUCT_LEVEL_PRODUCTGROUP, Collectors.mapping(x -> PermitTreeDRO.builder().permitId(x.getGroupId()).permitName(x.getName()).parentId(x.getBizLine()).level(PRODUCT_LEVEL_PRODUCTGROUP).dataSubAll(PlatEngineConsts.STATUS_VALID).build(), Collectors.toList())));
            groupMap.putAll(groups);
        }

        List<PermitTreeDRO> trees = Optional.ofNullable(staffDpermitService.listByStaffIdAndDataType(staffId, DpermitConsts.TYPE_PRODUCT)).orElse(Collections.emptyList()).stream().map(x -> PermitTreeDRO.builder().permitId(x.getDataId()).permitName(x.getDataName()).parentId(x.getDataParentId()).level(x.getDataLevel()).dataSubAll(x.getDataSubAll()).build()).collect(Collectors.toList());

        //
        if (CollectionUtil.isNotNullOrEmpty(trees)) {
            // 判断是否拥有全部
            trees.forEach(x -> {
                if (Objects.equals(x.getDataSubAll(), PlatEngineConsts.YES)) {
                    // 拥有全部子级
                    // 查询所有的子级
                    x.setPermitTreeDROS(findAllSubData(x.getPermitId(), x.getLevel() + 1, groupMap));
                }
            });
            return buildTree(trees);
        }

        // 员工没有则查询部门
        Integer deptId = staff.getDeptId();
        List<PermitTreeDRO> treeDROS = Optional.ofNullable(deptDpermitService.listByDeptIdAndDataType(deptId, TYPE_PRODUCT)).orElse(Collections.emptyList()).stream().map(x -> PermitTreeDRO.builder().permitId(x.getDataId()).permitName(x.getDataName()).parentId(x.getDataParentId()).level(x.getDataLevel()).dataSubAll(x.getDataSubAll()).build()).collect(Collectors.toList());
        if (CollectionUtil.isNotNullOrEmpty(treeDROS)) {
            // 判断是否拥有全部
            treeDROS.forEach(x -> {
                if (Objects.equals(x.getDataSubAll(), PlatEngineConsts.YES)) {
                    // 拥有全部子级
                    // 查询所有的子级
                    x.setPermitTreeDROS(findAllSubData(x.getPermitId(), x.getLevel() + 1, groupMap));
                }
            });
            return buildTree(treeDROS);
        }

        // 部门没有则用于全部的权限
        // 便利list 组装tree数组
        List<PermitTreeDRO> list = groupMap.get(TOP_LEVEL + "_" + PRODUCT_LEVEL_BIZTYPE);
        list.forEach(x -> {
            // 拥有全部子级
            // 查询所有的子级
            x.setDataSubAll(PlatEngineConsts.STATUS_VALID);
            x.setPermitTreeDROS(findAllSubData(x.getPermitId(), x.getLevel() + 1, groupMap));

        });

        // 构建树形
        return list;
    }

    private List<PermitTreeDRO> buildTree(List<PermitTreeDRO> list) {
        Map<Integer, List<PermitTreeDRO>> collect = list.stream().collect(Collectors.groupingBy(PermitTreeDRO::getParentId));
        list.forEach(x -> {
            List<PermitTreeDRO> sub = collect.get(x.getPermitId());
            if (CollectionUtil.isNotNullOrEmpty(sub)) {
                x.setPermitTreeDROS(sub);
            }
        });
        return collect.get(TOP_LEVEL);
    }

    private List<PermitTreeDRO> findAllSubData(Integer parentId, int level, Map<String, List<PermitTreeDRO>> groupMap) {

        List<PermitTreeDRO> permitTreeDROS = groupMap.get(parentId + "_" + level);
        if (CollectionUtil.isNullOrEmpty(permitTreeDROS)) {
            return Collections.emptyList();
        }
        permitTreeDROS.forEach(x -> {
            x.setPermitTreeDROS(findAllSubData(x.getPermitId(), level + 1, groupMap));
        });
        return permitTreeDROS;
    }

    /**
     * 描述: 查询下级权限
     *
     * @param listMap listMap 所有的权限
     * @param permits permits 上级全选
     * @return com.zmn.common.dto2.ResponseDTO<java.util.List < com.zmn.mcc.common.dto.permit.PermitDRO>>
     * @author jiafei
     * @since 2022/5/26 20:43
     */
    private List<PermitDRO> getSubPermit(Map<Integer, List<PermitDRO>> listMap, List<? extends DpermitBaseDO> permits) {

        List<PermitDRO> result = new ArrayList<>();
        // 判断 遍历权限  构建tree 将子权限查询出来
        permits.forEach(x -> {
            // 判断
            result.add(PermitDRO.builder()
                    .permitId(x.getDataId()).permitName(x.getDataName()).parentId(x.getDataParentId()).level(x.getDataLevel()).build());
            if (Objects.equals(x.getDataSubAll(), PlatEngineConsts.NO) || Objects.equals(x.getDataLevel(), PlatEngineConsts.LEVEL_3)) {
                return;
            }
            List<PermitDRO> permitDROS = listMap.get(x.getDataId());
            if (CollectionUtil.isNotNullOrEmpty(permitDROS)) {
                permitDROS.forEach(i -> i.setLevel(x.getDataLevel() + 1));
                result.addAll(permitDROS);
                permitDROS.forEach(e -> {

                    List<PermitDRO> list = listMap.get(e.getPermitId());

                    if (CollectionUtil.isNullOrEmpty(list)) {
                        return;
                    }
                    result.addAll(list);
                });
            }
        });
        return result;
    }


    private List<PermitDRO> getDeptSubPermit(Map<Integer, List<PermitDRO>> listMap, List<? extends DpermitBaseDO> permits, Map<Integer, Integer> deptMap) {

        List<PermitDRO> result = new ArrayList<>();
        // 判断 遍历权限  构建tree 将子权限查询出来
        permits.forEach(x -> {
            // 判断
            result.add(PermitDRO.builder()
                    .permitId(x.getDataId()).permitName(x.getDataName()).parentId(x.getDataParentId()).level(x.getDataLevel()).orgId(deptMap.get(x.getDataId())).build());
            if (Objects.equals(x.getDataSubAll(), PlatEngineConsts.NO) || Objects.equals(x.getDataLevel(), PlatEngineConsts.LEVEL_3)) {
                return;
            }
            List<PermitDRO> permitDROS = listMap.get(x.getDataId());
            if (CollectionUtil.isNotNullOrEmpty(permitDROS)) {
                permitDROS.forEach(i -> i.setLevel(x.getDataLevel() + 1));
                result.addAll(permitDROS);
            }
        });
        return result;
    }

    @Override
    public ResponseDTO addPermit(McPermit permit) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkPermit(permit);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initPermit(permit);

            // 权限信息
            permitService.insert(permit);

            return ResponseDTO.success(permit.getPermitId(), "新增权限成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]新增权限失败,permit:[%s],ex:[%s]", JSONObject.toJSONString(permit), ex.getMessage()));
            return ResponseDTO.fail("新增权限失败");
        }
    }

    @Override
    public ResponseDTO modifyPermit(McPermit permit) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkPermit(permit);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initPermit(permit);

            // 权限信息
            permitService.updateByKey(permit);

            return ResponseDTO.success(permit.getPermitId(), "修改权限成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]修改权限失败,permit:[%s],ex:[%s]", JSONObject.toJSONString(permit), ex.getMessage()));
            return ResponseDTO.fail("修改权限失败");
        }
    }

    /**
     * 校验权限信息
     *
     * @param permit
     * @return
     */
    private ResponseDTO checkPermit(McPermit permit) {

        if (StringUtil.isBlank(permit.getPermitName())) {
            return ResponseDTO.fail("权限名称不能为空");
        }
        if (NumberUtil.isNullOrZero(permit.getSysId())) {
            return ResponseDTO.fail("未指定系统");
        }
        if (NumberUtil.isNullOrZero(permit.getModuleId())) {
            return ResponseDTO.fail("未指定模块");
        }

        return ResponseDTO.success(null, "OK");
    }

    /**
     * 初始化权限
     *
     * @param permit
     */
    private void initPermit(McPermit permit) {

        // 权限Url
        if (!permit.getUrl().startsWith("/")) {
            permit.setUrl("/" + permit.getUrl());
        }
    }
    // endregion


    @Override
    public List<String> checkPermitUrls(Integer staffId, String app, List<String> urls) {
        // 获取sysId
        McSysQuery query = new McSysQuery();
        query.setSysName(app);
        query.setStatus(PlatEngineConsts.STATUS_VALID);
        List<McSys> mcSysList = sysService.listByQuery(query);
        if (CollectionUtil.isNullOrEmpty(mcSysList)) {
            return Collections.emptyList();
        }
        McSys mcSys = mcSysList.get(PlatEngineConsts.TOP_ID_NULL);
        SpermitDTO<PermitLitDO> permit = staffBService.listPermitBySysId(staffId, mcSys.getSysId());
        if (Objects.isNull(permit)) {
            return Collections.emptyList();
        }
        List<PermitLitDO> items = permit.getItems();
        if (CollectionUtil.isNullOrEmpty(items)) {
            return Collections.emptyList();
        }
        List<String> hasUrls = items.stream().map(PermitLitDO::getUrl).collect(Collectors.toList());
        return urls.stream().filter(hasUrls::contains).collect(Collectors.toList());

    }
}
